#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <symtab.h>

/*
 * symtab.c - Symbol Table for Pascal Compiler
 * 
 *  Index  | LexLvl | Categ |  Type  | Offset  | Label | param1 | param2 | ......
 *    0        0        0       0        0                        <------ Linha 0 nao utilizada. 
 *    1        7       VAR     int      -12       
 *    2        8      FUNCT   float     -16          1
 *
 */

char szLexTape[MAXIDLEXLEN];
char szLexVal[MAXIDLEXLEN];
int iSymtab[MAXSYMTABENTRIES][MAXSYMTABCOLUMNS];
int iLexLen=0, iLexIdx=0, iSymtab_NextEntry=1, iSymtab_NextProc = 1;
char *pch;

int symtab_lookup(char *lexeme){
  int ii=1;
  while ( ii < iSymtab_NextEntry ){ // scan all active entries.
    if ( !strcasecmp(&szLexTape[iSymtab[ii][0]], lexeme) )
      return ii; 
    
    ii++;
  }
  return 0;
}

int symtab_lookup_by_column(int iColumnID, int iColumnVal){
  int ii=1;
  while ( ii < iSymtab_NextEntry ){ // scan all active entries.
    if ( iSymtab[ii][iColumnID] == iColumnVal )
      return ii;
    
    ii++;
  }
  return 0;
}
int symtab_insert(char *lexeme){
  iLexLen = strlen(lexeme);
  if ( (iLexIdx + iLexLen) > MAXIDLEXLEN - 1 ) { // lextape overflow
    fprintf(stderr, "lextape overflow");
    return -1;
  }
  else if ( iSymtab_NextEntry > MAXSYMTABENTRIES - 1 ) { // symtab overflow
    fprintf(stderr, "symtab overflow");
    return -2;
  }
  if ( symtab_lookup(lexeme) ){                          // duplicate entry
    fprintf(stderr, "duplicate entry for symbol %s", lexeme);
    return -3;
  }
  // Check ok, Inserting
  iSymtab[iSymtab_NextEntry][SYMLXLVL] = giLexLevel;  // Lexical Level. 0 => GLOBAL | 1 => IN A PROCEDURE OR FUNCTION
  iSymtab[iSymtab_NextEntry][SYMLXIDX] = iLexIdx;  // lexeme index on lextape
  iSymtab[iSymtab_NextEntry][SYMLXCTG] = giLexCat;  // Var, Procedure, etc. 
  strcpy(&szLexTape[iLexIdx], lexeme); // write on Lextape
  iLexIdx += iLexLen;
  szLexTape[iLexIdx++] = 0; // Update Index and set last character as 0 
  return iSymtab_NextEntry++; 
}

void symtab_dispose(void){
  int ii;
  for ( ii = 1 ; ii < iSymtab_NextEntry ; ii++ ){
    if ( iSymtab[ii][1] == giLexLevel ){ // id do mesmo nivel lexico?
      strcpy(&szLexTape[iSymtab[ii][0]], " "); // excluindo.
      iSymtab[ii][0] = 21000; // grande o suficiente 
      iSymtab[ii][1] = 0; 
      iSymtab[ii][2] = 0; 
      iSymtab[ii][3] = 0; 
      iSymtab[ii][4] = 0; 
    }
  }
}